package com.macllvm.whale.net;

import android.util.Log;

import java.lang.InterruptedException;
import java.nio.channels.SocketChannel;
import java.nio.channels.FileChannel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.io.RandomAccessFile;
import java.io.File;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import com.macllvm.whale.protocol.PacketPackager;
import com.macllvm.whale.protocol.ProtocolBase;
import com.macllvm.whale.protocol.ProtocolController;
import com.macllvm.whale.entity.Transfer;
import com.macllvm.whale.model.IProgressCallback;


public class TCPFileRecvTask implements Callable<Integer> {
     private static final String TAG = "TCPFileRecvTask";
     private SocketChannel socketChannel;
     private Transfer transfer;
     private FileChannel fileChannel;
     private RandomAccessFile randomFile;
     private Selector selector;
     private ByteBuffer byteBuffer;
     private IProgressCallback progressCallback;
     private boolean isRunning = true;

     public TCPFileRecvTask(Transfer t, IProgressCallback callback) {
         transfer = t;
         progressCallback = callback;
     }


     @Override
     public Integer call() {
         try{

             File f = new File(transfer.filePath);
             if(f.exists()) {
                 f.delete();
             }

             randomFile = new RandomAccessFile(transfer.filePath, "rw");
             fileChannel = randomFile.getChannel();
             byteBuffer = ByteBuffer.allocate(256);
             byteBuffer.clear();
             socketChannel = SocketChannel.open(new InetSocketAddress(transfer.ip,
                                                    ProtocolBase.IPMSG_PORT));
             socketChannel.configureBlocking(false);
             //socketChannel.socket().setKeepAlive(true);
             socketChannel.socket().setSoTimeout(3000);
             //socketChannel.socket().setSendBufferSize(256);
             //socketChannel.socket().setReceiveBufferSize(256);

             selector = Selector.open();
             socketChannel.register(selector, SelectionKey.OP_READ);
             while (!socketChannel.finishConnect()) {
                 continue;
             }

             String attr = transfer.fileNumber + ":" + transfer.fileId + ":" + "0";
             String req = PacketPackager.packagePacket(ProtocolBase.IPMSG_GETFILEDATA, attr);
             socketChannel.write(ByteBuffer.wrap(req.getBytes()));


             int n = selector.select();
             if( n > 0) {
                  Iterator iterator = selector.selectedKeys().iterator();
                  while(iterator.hasNext()) {
                       SelectionKey key = (SelectionKey) iterator.next();
                       if(key.isReadable())
                           recvFileData(key);
                       iterator.remove();
                  }
             }
         }catch(IOException e){
             Log.e(TAG, e.toString());
         }catch(CancellationException e) {
             Log.e(TAG, e.toString());
         } finally {
             try {
                 if (null != socketChannel && socketChannel.isOpen())
                     socketChannel.close();
                 if (null != fileChannel && fileChannel.isOpen())
                     fileChannel.close();
                 if (null != randomFile)
                     randomFile.close();
             }catch(IOException e) {
                 e.printStackTrace();
             }
         }
         return 0;
     }

     private void recvFileData(SelectionKey key) throws IOException {
         SocketChannel socketChannel = (SocketChannel)key.channel();
         fileChannel.position(0);
         int readBytes = 0;
         long recvTotal = 0;

         transfer.state = Transfer.STATE_ONGOING;
         progressCallback.refreshProgress(transfer.index);
         long lastUpdateTime = 0;
         while( ( readBytes = socketChannel.read(byteBuffer) ) != -1 ) {
             byteBuffer.flip();
             fileChannel.write(byteBuffer);

             recvTotal += readBytes;
             transfer.percent = (int)( recvTotal / (double)transfer.fileSize * 100);
             byteBuffer.clear();

             long now = System.currentTimeMillis();
             if(now - lastUpdateTime > 1000) {
                 lastUpdateTime = now;
                 progressCallback.refreshProgress(transfer.index);
             }

             if(recvTotal == transfer.fileSize) {
                 transfer.state = Transfer.STATE_SUCCESS;
                 break;
             }
         }

         if(recvTotal == transfer.fileSize) {
             transfer.state = Transfer.STATE_SUCCESS;
         }else{
             transfer.state = Transfer.STATE_FAIL;
         }

         progressCallback.refreshProgress(transfer.index);

     }
}